home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / UUCP / UUXQT.C < prev   
C/C++ Source or Header  |  1993-04-10  |  51KB  |  1,428 lines

  1. /*
  2.       Program:    uuxqt.c              23 September 1991
  3.       Author:     Mitch Mitchell
  4.       Email:      mitch@harlie.lonestar.org
  5.  
  6.       This is a re-write of the (much cleaner) UUXQT.C originally
  7.       distributed with UUPC/Extended.  The modifications are
  8.       intended primarily to lay a foundation for support for the
  9.       more advanced features of UUX.
  10.  
  11.       Usage:      uuxqt -xDEBUG -sSYSTEM
  12.  
  13.       Last Revised: 26-Jan-1993
  14. */
  15.  
  16. /*--------------------------------------------------------------------*/
  17. /*                          RCS Information                           */
  18. /*--------------------------------------------------------------------*/
  19.  
  20. /*
  21.  *    $Id: UUXQT.C 1.7 1993/04/11 00:35:46 ahd Exp $
  22.  *
  23.  *    Revision history:
  24.  *    $Log: UUXQT.C $
  25.  * Revision 1.7  1993/04/11  00:35:46  ahd
  26.  * Global edits for year, TEXT, etc.
  27.  *
  28.  * Revision 1.6  1993/04/05  04:35:40  ahd
  29.  * Use timestamp/file size information returned by directory search
  30.  *
  31.  * Revision 1.5  1992/11/25  12:59:17  ahd
  32.  * Change NUL to /dev/nul to prevent ImportPath() mangling.
  33.  *
  34.  * Revision 1.4  1992/11/23  03:56:06  ahd
  35.  * Selected fixes for use of generlized uux commands
  36.  *
  37.  * Revision 1.3  1992/11/19  03:03:33  ahd
  38.  * drop rcsid
  39.  *
  40.  * Revision 1.2  1992/11/19  03:03:09  ahd
  41.  * Revision 1.1  1992/11/15  20:16:50  ahd
  42.  * Initial revision
  43.  *
  44.  * Revision 1.1  1992/04/27  02:46:02  ahd
  45.  * Initial revision
  46.  *
  47.  */
  48.  
  49.  
  50. /*--------------------------------------------------------------------*/
  51. /*                        System include files                        */
  52. /*--------------------------------------------------------------------*/
  53.  
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58. #include <errno.h>
  59. #include <time.h>
  60. #include <fcntl.h>
  61. #include <process.h>
  62. #include <sys/types.h>
  63. #include <sys/stat.h>
  64. #include <io.h>
  65.  
  66. /*--------------------------------------------------------------------*/
  67. /*                    UUPC/extended include files                     */
  68. /*--------------------------------------------------------------------*/
  69.  
  70. #include "lib.h"
  71. #include "arpadate.h"
  72. #include "dater.h"
  73. #include "expath.h"
  74. #include "getopt.h"
  75. #include "getseq.h"
  76. #include "hlib.h"
  77. #include "hostable.h"
  78. #include "import.h"
  79. #include "lock.h"
  80. #include "logger.h"
  81. #include "pushpop.h"
  82. #include "readnext.h"
  83. #include "security.h"
  84. #include "timestmp.h"
  85. #include "usertabl.h"
  86.  
  87. currentfile();
  88.  
  89. /*--------------------------------------------------------------------*/
  90. /*                      Execution flag defines                        */
  91. /*--------------------------------------------------------------------*/
  92.  
  93. typedef enum {
  94.         X_OUTPUT,     /* 'O' return output to "outnode"       */
  95.         X_FAILED,     /* 'Z' send status if command failed    */
  96.         X_SUCCESS,    /* 'n' send status if command succeeded */
  97.         X_INPUT,      /* 'B' return command input on error    */
  98.         X_USEEXEC,    /* 'E' process command using exec(2)    */
  99.         X_STATFIL,    /* 'M' return status to file on remote  */
  100.  
  101.         S_CORRUPT,
  102.         S_EMPTY,
  103.         S_NOREAD,
  104.         S_NOWRITE,
  105.         S_STDIN,
  106.  
  107.         E_NORMAL,
  108.         E_NOACC,
  109.         E_SIGNAL,
  110.         E_STATUS,
  111.         E_NOEXE,
  112.         E_FAILED,
  113.  
  114.         UU_LAST,
  115.  
  116.         } UU_FLAGS;
  117.  
  118. /*--------------------------------------------------------------------*/
  119. /*                          Global Variables                          */
  120. /*--------------------------------------------------------------------*/
  121.  
  122. static char *spool_fmt = SPOOLFMT;
  123. static char *dataf_fmt = DATAFFMT;
  124. static char *send_cmd  = "S %s %s %s -%s %s 0666 %s\n";
  125.  
  126. /*--------------------------------------------------------------------*/
  127. /*                        Internal prototypes                         */
  128. /*--------------------------------------------------------------------*/
  129.  
  130. static void usage( void );
  131.  
  132. static boolean copylocal(const char *from, const char *to);
  133.  
  134. static boolean do_uuxqt( const char *sysname );
  135.  
  136. static void process( const char *fname, const char *remote );
  137.  
  138. char **create_environment(const char *logname,
  139.                           const char *requestor);
  140.  
  141. static void delete_environment( char **envp);
  142.  
  143. static boolean AppendData( const char *input, FILE* dataout);
  144.  
  145. static boolean do_copy( char *localfile,
  146.                        const char *rmtsystem,
  147.                        const char *remotefile,
  148.                        const char *requestor,
  149.                        const boolean success );
  150.  
  151. static void ReportResults(const int   status,
  152.                           const char *input,
  153.                                 char *output,
  154.                           const char *command,
  155.                           const char *job_id,
  156.                           const time_t jtime,
  157.                           const char *requestor,
  158.                           const char *outnode,
  159.                           const char *outname,
  160.                           const boolean xflag[],
  161.                           const char *statfil,
  162.                           const char *machine,
  163.                           const char *user);
  164.  
  165. static int shell(char *command,
  166.                  const char *inname,
  167.                  const char *outname,
  168.                  const char *remotename,
  169.                  boolean xflag[]);
  170.  
  171. static boolean MailStatus(char *tempfile,
  172.                           char *address,
  173.                           char *subject);
  174.  
  175. static boolean internal( char *command );
  176.  
  177. /*--------------------------------------------------------------------*/
  178. /*    m a i n                                                         */
  179. /*                                                                    */
  180. /*    Main program                                                    */
  181. /*--------------------------------------------------------------------*/
  182.  
  183. void main( int argc, char **argv)
  184. {
  185.    int c;
  186.    extern char *optarg;
  187.    extern int   optind;
  188.    char *sysname = "all";
  189.  
  190. /*--------------------------------------------------------------------*/
  191. /*     Report our version number and date/time compiled               */
  192. /*--------------------------------------------------------------------*/
  193.  
  194.    debuglevel = 1;
  195.    banner( argv );
  196.  
  197. #if defined(__CORE__)
  198.    copywrong = strdup(copyright);
  199.    checkref(copywrong);
  200. #endif
  201.  
  202. /*--------------------------------------------------------------------*/
  203. /*        Process our arguments                                       */
  204. /*--------------------------------------------------------------------*/
  205.  
  206.    while ((c = getopt(argc, argv, "s:x:")) !=  EOF)
  207.       switch(c) {
  208.  
  209.       case 's':
  210.          sysname = optarg;
  211.          break;
  212.  
  213.       case 'x':
  214.          debuglevel = atoi( optarg );
  215.          break;
  216.  
  217.       case '?':
  218.          usage();
  219.          exit(1);
  220.          break;
  221.  
  222.       default:
  223.          printmsg(0, "uuxqt - invalid option -%c", c);
  224.          usage();
  225.          exit(2);
  226.          break;
  227.    }
  228.  
  229.    if (optind != argc) {
  230.       fputs("Extra parameter(s) at end.\n", stderr);
  231.       usage();
  232.       exit(2);
  233.    }
  234.  
  235. /*--------------------------------------------------------------------*/
  236. /*                             Initialize                             */
  237. /*--------------------------------------------------------------------*/
  238.  
  239.    tzset();                      /* Set up time zone information  */
  240.  
  241.    if (!configure( B_UUXQT ))
  242.       exit(1);   /* system configuration failed */
  243.  
  244. /*--------------------------------------------------------------------*/
  245. /*                  Switch to the spooling directory                  */
  246. /*--------------------------------------------------------------------*/
  247.  
  248.    PushDir( E_spooldir );
  249.    atexit( PopDir );
  250.  
  251. /*--------------------------------------------------------------------*/
  252. /*                     Initialize logging file                        */
  253. /*--------------------------------------------------------------------*/
  254.  
  255.    openlog( NULL );
  256.  
  257.    checkuser( E_mailbox  );   /* Force User Table to initialize      */
  258.    checkreal( E_mailserv );   /* Force Host Table to initialize      */
  259.  
  260.    if (!LoadSecurity())
  261.    {
  262.       printmsg(0,"Unable to initialize security, see previous message");
  263.       exit(2);
  264.    } /* if (!LoadSecurity()) */
  265.  
  266. /*--------------------------------------------------------------------*/
  267. /*                Set up search path for our programs                 */
  268. /*--------------------------------------------------------------------*/
  269.  
  270.    if ( E_uuxqtpath != NULL )
  271.    {
  272.       char *p = malloc( 6 + strlen( E_uuxqtpath ));
  273.       checkref( p );
  274.              /*  ....+        5 characters plus \0 and length of path */
  275.       sprintf(p,"PATH=%s", E_uuxqtpath);
  276.  
  277.       if (putenv( p ))
  278.       {
  279.          printmsg(0,"Unable to set path \"%s\"", p);
  280.          panic();
  281.       } /* if (putenv( p )) */
  282.    } /* if ( E_uuxqtpath != NULL ) */
  283.  
  284. /*--------------------------------------------------------------------*/
  285. /*              Disable OS/2 undelete support if desired              */
  286. /*--------------------------------------------------------------------*/
  287.  
  288.    if ( !bflag[ F_UNDELETE ] )
  289.       putenv( "DELDIR=");
  290.  
  291. /*--------------------------------------------------------------------*/
  292. /*    Actually invoke the processing routine for the eXecute files    */
  293. /*--------------------------------------------------------------------*/
  294.  
  295.    do_uuxqt( sysname );
  296.    if( equal( sysname , "all" ) )
  297.        do_uuxqt( E_nodename );
  298.  
  299.    exit(0);
  300.  
  301. } /* main */
  302.  
  303. /*--------------------------------------------------------------------*/
  304. /*    d o _ u u x q t                                                 */
  305. /*                                                                    */
  306. /*    Processing incoming eXecute (X.*) files for a remote system     */
  307. /*--------------------------------------------------------------------*/
  308.  
  309. static boolean do_uuxqt( const char *sysname )
  310. {
  311.    struct HostTable *hostp;
  312.    static char uu_machine[] = UU_MACHINE "=";
  313.    char hostenv[sizeof uu_machine + 25 + 2];
  314.  
  315. /*--------------------------------------------------------------------*/
  316. /*                 Determine if we have a valid host                  */
  317. /*--------------------------------------------------------------------*/
  318.  
  319.    if( !equal( sysname , "all" ) ) {
  320.       if (equal( sysname , E_nodename ))
  321.           hostp = checkname( sysname );
  322.       else
  323.           hostp = checkreal( sysname );
  324.  
  325.       if (hostp  ==  BADHOST) {
  326.          printmsg(0, "Unknown host \"%s\".", sysname );
  327.          exit(1);
  328.       }
  329.  
  330.    } else
  331.         hostp = nexthost( TRUE );
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*             Outer loop for processing different hosts              */
  335. /*--------------------------------------------------------------------*/
  336.  
  337.    while  (hostp != BADHOST)
  338.    {
  339.       char fname[FILENAME_MAX];
  340.       boolean locked = FALSE;
  341.  
  342. /*--------------------------------------------------------------------*/
  343. /*                Initialize security for this remote                 */
  344. /*--------------------------------------------------------------------*/
  345.  
  346.       if ( !equal(sysname, E_nodename) &&
  347.            (securep = GetSecurity( hostp )) == NULL )
  348.          printmsg(0,"No security defined for \"%s\","
  349.                   " cannot process X.* files",
  350.                   hostp->hostname );
  351.       else {
  352.  
  353. /*--------------------------------------------------------------------*/
  354. /*              Set up environment for the machine name               */
  355. /*--------------------------------------------------------------------*/
  356.  
  357.       sprintf(hostenv,"%s%.25s", uu_machine, hostp->hostname);
  358.  
  359.       if (putenv( hostenv ))
  360.       {
  361.          printmsg(0,"Unable to set environment \"%s\"",hostenv);
  362.          panic();
  363.       }
  364.  
  365. /*--------------------------------------------------------------------*/
  366. /*           Inner loop for processing files from one host            */
  367. /*--------------------------------------------------------------------*/
  368.  
  369.          while (readnext(fname, hostp->hostname, "X", NULL, NULL, NULL) )
  370.             if ( locked || LockSystem( hostp->hostname , B_UUXQT ))
  371.             {
  372.                process( fname , hostp->hostname );
  373.                locked = TRUE;
  374.             }
  375.             else
  376.                break;               /* We didn't get the lock        */
  377.  
  378.          if ( locked )
  379.             UnlockSystem();
  380.  
  381.       } /* else if */
  382.  
  383. /*--------------------------------------------------------------------*/
  384. /*                        Restore environment                         */
  385. /*--------------------------------------------------------------------*/
  386.  
  387.       putenv( uu_machine );   /* Reset to empty string               */
  388.  
  389. /*--------------------------------------------------------------------*/
  390. /*    If processing all hosts, step to the next host in the queue     */
  391. /*--------------------------------------------------------------------*/
  392.  
  393.       if( equal(sysname,"all") )
  394.          hostp = nexthost( FALSE );
  395.       else
  396.          hostp = BADHOST;
  397.  
  398.    } /*while nexthost*/
  399.  
  400.    return FALSE;
  401.  
  402. } /* do_uuxqt */
  403.  
  404. /*--------------------------------------------------------------------*/
  405. /*    p r o c e s s                                                   */
  406. /*                                                                    */
  407. /*    Process a single execute file                                   */
  408. /*--------------------------------------------------------------------*/
  409.  
  410. static void process( const char *fname, const char *remote )
  411. {
  412.    char *command = NULL,
  413.         *input = NULL,
  414.         *output = NULL,
  415.         *job_id = NULL,
  416.         *token = NULL,
  417.         line[BUFSIZ];
  418.    char hostfile[FILENAME_MAX];
  419.    boolean skip = FALSE;
  420.    boolean reject = FALSE;
  421.    FILE *fxqt;
  422.    int   status;
  423.  
  424.    char *outnode = NULL;
  425.    char *outname = NULL;
  426.    char *user = NULL;
  427.    char *requestor = NULL;
  428.    char *statfil = NULL;
  429.    char *machine = NULL;
  430.    char   **envp;
  431.  
  432.    boolean xflag[UU_LAST - 1] = { 0 };
  433.    time_t jtime = time(NULL);
  434.  
  435. /*--------------------------------------------------------------------*/
  436. /*                         Open the X.* file                          */
  437. /*--------------------------------------------------------------------*/
  438.  
  439.    if ( (fxqt = FOPEN(fname, "r", BINARY_MODE)) == NULL) {  /* inbound X.* file */
  440.       printerr(fname);
  441.       return;
  442.    }
  443.    else
  444.       printmsg(2, "processing %s", fname);
  445.  
  446. /*--------------------------------------------------------------------*/
  447. /*                  Begin loop to read the X.* file                   */
  448. /*--------------------------------------------------------------------*/
  449.  
  450.    while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL)) {
  451.       char *cp;
  452.  
  453.       if ( (cp = strchr(line, '\n')) != NULL )
  454.          *cp = '\0';
  455.  
  456.       printmsg(8, "input read: %s", line);
  457.  
  458. /*--------------------------------------------------------------------*/
  459. /*            Process the input line according to its type            */
  460. /*--------------------------------------------------------------------*/
  461.  
  462.       switch (line[0])
  463.       {
  464.  
  465.       case '#':
  466.          break;
  467.  
  468. /*--------------------------------------------------------------------*/
  469. /*                  User which submitted the command                  */
  470. /*--------------------------------------------------------------------*/
  471.  
  472.       case 'U':
  473.          strtok(line," \t\n");      /* Trim off leading "U"       */
  474.                                     /* Get the user name          */
  475.          if ( (cp = strtok(NULL," \t\n")) == NULL ) {
  476.             printmsg(0,"No user on U line in file \"%s\"", fname );
  477.          } else {
  478.              user = strdup(cp);
  479.              checkref(user);
  480.          };
  481.                                     /* Get the system name        */
  482.          if ( (cp = strtok(NULL," \t\n")) == NULL)
  483.          {                          /* Did we get a string?       */
  484.             printmsg(2,"No node on U line in file \"%s\"", fname );
  485.             cp = (char *) remote;
  486.          } else if (!equal(cp,remote)) {
  487.             printmsg(2,"Node on U line in file \"%s\" doesn't match remote",
  488.                      fname );
  489.             cp = (char * ) remote;
  490.          };
  491.          machine = newstr(cp);
  492.          break;
  493.  
  494. /*--------------------------------------------------------------------*/
  495. /*                       Input file for command                       */
  496. /*--------------------------------------------------------------------*/
  497.  
  498.       case 'I':
  499.          input = strdup( &line[2] );                     /* ahd   */
  500.          checkref(input);
  501.          if (!equal(remote, E_nodename))
  502.             if (!(equaln(input,"D.",2) || ValidateFile( input, ALLOW_READ)))
  503.             {
  504.                 reject = TRUE;
  505.                 xflag[S_NOREAD] = TRUE;
  506.             }
  507.          break;
  508.  
  509. /*--------------------------------------------------------------------*/
  510. /*                      Output file for command                       */
  511. /*--------------------------------------------------------------------*/
  512.  
  513.       case 'O':
  514.          strtok(line," \t\n");      /* Trim off leading "U"       */
  515.                                     /* Get the user name          */
  516.          if ( (cp = strtok(NULL," \t\n")) != NULL )
  517.          {
  518.              outname = strdup(cp);
  519.              checkref(outname);
  520.              xflag[X_OUTPUT] = TRUE;  /* return output to "outnode" */
  521.              if ( (cp = strtok(NULL," \t\n")) != NULL)
  522.              {                /* Did we get a string?                */
  523.                    outnode = strdup(cp);
  524.                    checkref(outnode);
  525.                    checkreal(outnode);
  526.              }
  527.              else if (!equal(remote, E_nodename))
  528.              {
  529.                 if (!(equaln(outname,"D.",2) || ValidateFile( outname, ALLOW_WRITE)))
  530.                 {
  531.                     reject = TRUE;
  532.                     xflag[S_NOWRITE] = TRUE;
  533.                 } /* if */
  534.              } /* else if (!equal(remote, E_nodename)) */
  535.          } /* if ( (cp = strtok(NULL," \t\n")) != NULL ) */
  536.          break;
  537.  
  538. /*--------------------------------------------------------------------*/
  539. /*                         Command to execute                         */
  540. /*--------------------------------------------------------------------*/
  541.  
  542.       case 'C':
  543.          command = strdup( &line[2] );                   /* ahd   */
  544.          checkref(command);                              /* ahd   */
  545.          break;
  546.  
  547. /*--------------------------------------------------------------------*/
  548. /*                      Job Id for status reporting                   */
  549. /*--------------------------------------------------------------------*/
  550.  
  551.       case 'J':
  552.          strtok(line," \t\n");      /* Trim off leading "J"       */
  553.                                     /* Get the job id             */
  554.          if ( (cp = strtok(NULL," \t\n")) == NULL )
  555.          {
  556.             printmsg(0,"No job id on J line in file \"%s\"", fname );
  557.             reject = TRUE;
  558.          }
  559.          else {
  560.             job_id = strdup( cp );
  561.             checkref( job_id );
  562.          } /* else */
  563.          break;
  564.  
  565. /*--------------------------------------------------------------------*/
  566. /*                 Check that a required file exists                  */
  567. /*--------------------------------------------------------------------*/
  568.  
  569.       case 'F':
  570.          token = strtok(&line[1]," ");
  571.          importpath(hostfile, token, remote);
  572.  
  573.          if ( access( hostfile, 0 ))   /* Does the host file exist?  */
  574.          {                             /* No --> Skip the file       */
  575.             printmsg(0,"Missing file %s (%s) for %s, command skipped",
  576.                      token, hostfile, fname);
  577.             skip = TRUE;
  578.          }
  579.  
  580.          break;
  581.  
  582. /*--------------------------------------------------------------------*/
  583. /*             Requestor name (overrides user name, above)            */
  584. /*--------------------------------------------------------------------*/
  585.  
  586.       case 'R':
  587.          strtok(line," \t\n");      /* Trim off leading "R"       */
  588.                                     /* Get the user name          */
  589.          if ( (cp = strtok(NULL," \t\n")) == NULL )
  590.             printmsg(0,"No requestor on R line in file \"%s\"", fname );
  591.          else {
  592.             requestor = strdup(cp);
  593.             checkref(requestor);
  594.          }
  595.          break;
  596.  
  597. /*--------------------------------------------------------------------*/
  598. /*        Status file name to return info to on remote node           */
  599. /*--------------------------------------------------------------------*/
  600.  
  601.       case 'M':
  602.          strtok(line," \t\n");      /* Trim off leading "M"           */
  603.                                     /* Get the file name              */
  604.          if ( (cp = strtok(NULL," \t\n")) != NULL ) {
  605.             statfil = strdup(cp);
  606.             checkref(statfil);
  607.             xflag[X_STATFIL] = TRUE;     /* return status to remote file   */
  608.          } else {
  609.             printmsg(0,"No file name on M line in file \"%s\"", fname);
  610.          }
  611.          break;
  612.  
  613. /*--------------------------------------------------------------------*/
  614. /*                            Flag fields                             */
  615. /*--------------------------------------------------------------------*/
  616.  
  617.       case 'Z': xflag[X_FAILED] = TRUE;   /* send status if command failed */
  618.          break;
  619.  
  620.       case 'N': xflag[X_FAILED] = FALSE;  /* send NO status if command failed */
  621.          break;
  622.  
  623.       case 'n': xflag[X_SUCCESS] = TRUE;  /* send status if command succeeded */
  624.          break;
  625.  
  626.       case 'z': xflag[X_SUCCESS] = FALSE; /* NO status if command succeeded */
  627.          break;
  628.  
  629.       case 'B': xflag[X_INPUT] = TRUE;    /* return command input on error */
  630.          break;
  631.  
  632.       case 'e': xflag[X_USEEXEC] = FALSE; /* process command using sh(1) */
  633.          break;
  634.  
  635.       case 'E': xflag[X_USEEXEC] = TRUE;  /* process command using exec(2) */
  636.          break;
  637.  
  638. /*--------------------------------------------------------------------*/
  639. /*                    Quietly ignore unknown fields                   */
  640. /*--------------------------------------------------------------------*/
  641.  
  642.       default :
  643.          break;
  644.  
  645.       } /* switch */
  646.    } /* while (!skip & (fgets(line, BUFSIZ, fxqt) != NULL)) */
  647.  
  648.    if ( fxqt != NULL )
  649.       fclose(fxqt);
  650.  
  651.  
  652.    if ((command == NULL) && !skip)
  653.    {
  654.       printmsg(0,"No command supplied for X.* file %s, skipped", fname);
  655.       reject = TRUE;
  656.    }
  657.  
  658. /*--------------------------------------------------------------------*/
  659. /*           We have the data for this command; process it            */
  660. /*--------------------------------------------------------------------*/
  661.  
  662.    if ( ! (skip || reject ))
  663.    {
  664.       if ( user == NULL )
  665.       {
  666.          user = strdup("uucp");    /* User if none given         */
  667.          checkref(user);
  668.       }
  669.  
  670.       if (requestor == NULL)
  671.       {
  672.          requestor = strdup(user);
  673.          checkref(requestor);
  674.       }
  675.  
  676.       if (input == NULL)
  677.          input = strdup("/dev/nul");
  678.  
  679.       if (output == NULL)
  680.          output = mktempname(NULL, "OUT");
  681.  
  682.       printmsg(equaln(command,RMAIL,5) ? 2 : 0,
  683.                "uuxqt: executing \"%s\" for user \"%s\" at  \"%s\"",
  684.                    command, user, machine);
  685.  
  686. /*--------------------------------------------------------------------*/
  687. /*             Create the environment and run the command             */
  688. /*--------------------------------------------------------------------*/
  689.  
  690.       envp = create_environment("uucp", requestor);
  691.       status = shell(command, input, output, remote, xflag );
  692.       delete_environment(envp);
  693.  
  694.       ReportResults( status, input, output, command, job_id,
  695.                      jtime, requestor, outnode, outname, xflag,
  696.                      statfil, machine, user);
  697.  
  698. /*--------------------------------------------------------------------*/
  699. /*                  Clean up files after the command                  */
  700. /*--------------------------------------------------------------------*/
  701.  
  702.       unlink(fname);       /* Already a local file name            */
  703.  
  704.       if (equaln(input,"D.",2))
  705.       {
  706.           importpath(hostfile, input, remote);
  707.           unlink(hostfile);
  708.       }
  709.  
  710.       if (xflag[X_OUTPUT])
  711.       {
  712.           importpath(hostfile, output, remote);
  713.           unlink(hostfile);
  714.       }
  715.  
  716.    }
  717.    else if (reject && !skip)
  718.         unlink(fname);       /* Already a local file name            */
  719.  
  720. /*--------------------------------------------------------------------*/
  721. /*              Free various temporary character strings              */
  722. /*--------------------------------------------------------------------*/
  723.  
  724.    if (command    != NULL) free(command);
  725.    if (input      != NULL) free(input);
  726.    if (job_id     != NULL) free(job_id);
  727.    if (outnode    != NULL) free(outnode);
  728.    if (output     != NULL) free(output);
  729.    if (requestor  != NULL) free(requestor);
  730.    if (statfil    != NULL) free(statfil);
  731.    if (user       != NULL) free(user);
  732.  
  733. } /* process */
  734.  
  735. /*--------------------------------------------------------------------*/
  736. /*    s h e l l                                                       */
  737. /*                                                                    */
  738. /*    Simulate a Unix command                                         */
  739. /*--------------------------------------------------------------------*/
  740.  
  741. static int shell(char *command,
  742.                  const char *inname,
  743.                  const char *outname,
  744.                  const char *remotename,
  745.                  boolean xflag[])
  746. {
  747.    char  *argv[50];
  748.    int    argc;
  749.    int    result = 0;
  750.    char   inlocal[FILENAME_MAX];
  751.    char   outlocal[FILENAME_MAX];
  752.    char   savecmd[BUFSIZ];
  753.  
  754.    if (xflag[X_USEEXEC])
  755.       printmsg(2, "exec(2) not supported, executing using spawn");
  756.  
  757.    strcpy( savecmd, command );
  758.    argc = getargs(command, argv);
  759.  
  760.    printmsg(2,"uux: command arg count = %d", argc);
  761.    if (debuglevel >= 2) {
  762.       char **argvp = argv;
  763.       int i = 0;
  764.       while (i < argc)
  765.          printmsg(2, "shell: argv[%d]=\"%s\"", i++, *argvp++);
  766.    }
  767.  
  768. /*--------------------------------------------------------------------*/
  769. /*    Verify we support the command, and get it's real name, if so    */
  770. /*--------------------------------------------------------------------*/
  771.  
  772.    if ( (!equal(remotename, E_nodename)) && (!ValidateCommand( argv[0] )) )
  773.    {
  774.       printmsg(0,"Command \"%s\" not allowed at this site", argv[0]);
  775.       xflag[E_NOEXE] = TRUE;
  776.       return 99;
  777.    }
  778.  
  779. /*--------------------------------------------------------------------*/
  780. /*                     Open files for processing                      */
  781. /*--------------------------------------------------------------------*/
  782.  
  783.    if (inname != NULL)
  784.    {
  785.       importpath(inlocal, inname, remotename);
  786.       printmsg(2, "shell: opening %s for input", inlocal);
  787.       if (freopen(inlocal, "rb", stdin) == NULL)
  788.       {
  789.          printmsg(0, "shell: couldn't open %s (%s), errno=%d.",
  790.             inname, inlocal, errno);
  791.          printerr(inlocal);
  792.          xflag[S_CORRUPT] = TRUE;
  793.          return -2;
  794.       }
  795.    }
  796.  
  797.    if (outname != NULL)
  798.    {
  799.       importpath(outlocal, outname, remotename);
  800.       printmsg(2, "shell: opening %s for output", outlocal);
  801.       if (freopen(outlocal, "wt", stdout) == NULL) {
  802.          printmsg(0, "shell: couldn't open %s (%s), errno=%d.",
  803.             outname, outlocal, errno);
  804.          printerr(outlocal);
  805.          if ( inname != NULL)
  806.             freopen("con", "rt", stdin);
  807.          xflag[S_NOWRITE] = TRUE;
  808.          return -2;
  809.       }
  810.    }
  811.  
  812. /*--------------------------------------------------------------------*/
  813. /*               We support the command; execute it                   */
  814. /*--------------------------------------------------------------------*/
  815.  
  816.    argv[argc] = NULL;
  817.    fflush(logfile);
  818.  
  819.    if (equal(argv[0],RMAIL) && ( inname != NULL )) /* Rmail w/input? */
  820.    {
  821.       int addr = 1;
  822.  
  823.       while (( addr < argc )  && (result != -1 ))
  824.       {
  825. #ifdef __TURBOC__
  826.          size_t rlen =  126 ;
  827. #else
  828.          size_t rlen = (_osmode == DOS_MODE) ? 126 :  254;
  829. #endif
  830.          char buf[255];
  831.          rlen -= strlen( argv[0] );
  832.                               /* Compute space left on command line  */
  833.          *buf = '\0';         /* Terminate the buffer string         */
  834.  
  835. /*--------------------------------------------------------------------*/
  836. /*                   Copy addresses into the buffer                   */
  837. /*--------------------------------------------------------------------*/
  838.  
  839.          while (( addr < argc ) && (rlen >= strlen( argv[addr] )))
  840.          {
  841.             if ( *argv[addr] == '-')   /* Option flag for mail?      */
  842.             {
  843.                printmsg(0,"Disallowed option %s ignored",argv[addr]);
  844.                continue;
  845.             }
  846.  
  847.             strcat( buf, argv[addr] );
  848.             rlen -= strlen( argv[addr++] ) + 1;
  849.             if (rlen > 0)     /* Room for another address?           */
  850.                strcat( buf, " ");   /* Yes --> Add space after addr  */
  851.          } /* while (( addr < argc ) && (rlen >= strlen( argv[addr] ) */
  852.  
  853.          if (*buf == '\0')    /* Did we process at least one addr?   */
  854.          {                    /* No --> Serious problem!             */
  855.             printmsg(0,"shell: address \"%s\" too long to process!",
  856.                   argv[addr] );
  857.             panic();
  858.          } /* if (*buf = '\0') */
  859.  
  860. /*--------------------------------------------------------------------*/
  861. /*               Execute one command line of addresses                */
  862. /*--------------------------------------------------------------------*/
  863.  
  864.          printmsg(2, "shell: %s %s", argv[0], buf );
  865.  
  866.          result = spawnlp( P_WAIT, argv[0], argv[0], buf , NULL);
  867.  
  868.          if (freopen(inlocal, "rb", stdin) == NULL)
  869.          {
  870.             printmsg(0, "shell: couldn't reopen %s (%s), errno=%d.",
  871.                inname, inlocal, errno);
  872.             printerr(inlocal);
  873.             panic();
  874.          } /* if */
  875.  
  876.          if ( result != 0 )
  877.          {
  878.             if (result == -1)       /* Did spawn fail?               */
  879.                printerr(argv[0]);   /* Yes --> Report error          */
  880.             printmsg(0,"shell: command \"%s %s\" returned error code %d",
  881.                      argv[0], buf, result);
  882.             panic();
  883.          }
  884.       } /* while (( addr < argc )  && (result != -1 )) */
  885.  
  886.    } /* if (equal(argv[0],RMAIL) && ( inname != NULL )) */
  887.    else if (internal(argv[0]))  /* Internal command?             */
  888.    {
  889.       result = system( savecmd );
  890.                               /* Use COMMAND.COM to run command   */
  891.    } /* else  if (internal(argv[0])) */
  892.    else  {                    /* No --> Invoke normally           */
  893.       result = spawnvp( P_WAIT, argv[0], argv );
  894.  
  895.    } /* else */
  896.  
  897. /*--------------------------------------------------------------------*/
  898. /*                    Determine result of command                     */
  899. /*--------------------------------------------------------------------*/
  900.  
  901.    if ( result == 0 )
  902.       xflag[E_NORMAL] = TRUE;
  903.    else if ( result > 0 )
  904.       xflag[E_STATUS] = TRUE;
  905.  
  906.    if (result == -1)       /* Did spawn fail?                     */
  907.       printerr(argv[0]);   /* Yes --> Report error                */
  908.  
  909. /*--------------------------------------------------------------------*/
  910. /*                  Re-open our standard i/o streams                  */
  911. /*--------------------------------------------------------------------*/
  912.  
  913.    errno = 0;
  914.  
  915.    if ( outname != NULL )
  916.       freopen("con", "wt", stdout);
  917.  
  918.    errno = 0;
  919.  
  920.    if ( inname != NULL )
  921.    {
  922.       FILE *temp = freopen("con", "rt", stdin);
  923.       if ( (temp == NULL) && (errno != 0) )
  924.       {
  925.          printerr("stdin");
  926.          panic();
  927.       }
  928.    } /* if ( inname != NULL ) */
  929.  
  930. /*--------------------------------------------------------------------*/
  931. /*                     Report results of command                      */
  932. /*--------------------------------------------------------------------*/
  933.  
  934.    printmsg( (result == 0 ) ? 8 : 1,"Result of spawn %s is ... %d",
  935.                                  argv[0], result);
  936.    fflush(logfile);
  937.  
  938.    return result;
  939.  
  940. } /*shell*/
  941.  
  942. /*--------------------------------------------------------------------*/
  943. /*    u s a g e                                                       */
  944. /*                                                                    */
  945. /*    Report how to run this program                                  */
  946. /*--------------------------------------------------------------------*/
  947.  
  948. static void usage( void )
  949. {
  950.    fputs("Usage:\tuuxqt\t[-xDEBUG] [-sSYSTEM]", stderr);
  951.    exit(1);
  952. } /* usage */
  953.  
  954. /*--------------------------------------------------------------------*/
  955. /*    c o p y l o c a l                                               */
  956. /*                                                                    */
  957. /*    Copy Local Files                                                */
  958. /*--------------------------------------------------------------------*/
  959.  
  960. static boolean copylocal(const char *from, const char *to)
  961. {
  962.       int  fd_from, fd_to;
  963.       int  nr;
  964.       int  nw = -1;
  965.       char buf[BUFSIZ];            /* faster if we alloc a big buffer */
  966.  
  967.       /* This would be even faster if we determined that both files
  968.          were on the same device, dos >= 3.0, and used the dos move
  969.          function */
  970.  
  971.       if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  972.          return FALSE;        /* failed */
  973.  
  974.       /* what if the to is a directory? */
  975.       /* possible with local source & dest uucp */
  976.  
  977.       if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  978.          close(fd_from);
  979.          return FALSE;        /* failed */
  980.          /* NOTE - this assumes all the required directories exist!  */
  981.       }
  982.  
  983.       while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  984.          (nw = write(fd_to, buf, nr)) == nr)
  985.          ;
  986.  
  987.       close(fd_to);
  988.       close(fd_from);
  989.  
  990.       if (nr != 0 || nw == -1)
  991.          return FALSE;        /* failed in copy */
  992.       return TRUE;
  993. } /* copylocal */
  994.  
  995. /*--------------------------------------------------------------------*/
  996. /*    c r e a t e _ e n v i r o n m e n t                             */
  997. /*                                                                    */
  998. /*    Create the environment array for subprocesses                   */
  999. /*--------------------------------------------------------------------*/
  1000.  
  1001. char **create_environment(const char *logname,
  1002.                           const char *requestor)
  1003. {
  1004.    char buffer[MAXADDR + 20];
  1005.    int subscript = 0;
  1006.    char **envp = (char **) malloc(sizeof(char *) * 3);
  1007.  
  1008.    checkref(envp);
  1009.  
  1010. /*--------------------------------------------------------------------*/
  1011. /*              "Current" user id processing the request              */
  1012. /*--------------------------------------------------------------------*/
  1013.  
  1014.    if ( logname != NULL )
  1015.    {
  1016.      sprintf(buffer,"%s=%s", LOGNAME, logname);
  1017.      envp[subscript] = strdup(buffer);
  1018.      checkref(envp[subscript++]);
  1019.    }
  1020.  
  1021. /*--------------------------------------------------------------------*/
  1022. /*               user id/nodename of original requestor               */
  1023. /*--------------------------------------------------------------------*/
  1024.  
  1025.    if ( requestor != NULL )
  1026.    {
  1027.       sprintf(buffer,"%s=%s",UU_USER, requestor);
  1028.       envp[subscript] =  strdup(buffer);
  1029.       checkref(envp[subscript++]);
  1030.    }
  1031.  
  1032.    envp[subscript] =  NULL;   /* Terminate the list                  */
  1033.  
  1034. /*--------------------------------------------------------------------*/
  1035. /*               Now put the data into our environment                */
  1036. /*--------------------------------------------------------------------*/
  1037.  
  1038.    while( subscript-- > 0)
  1039.    {
  1040.       if (putenv( envp[subscript] ))
  1041.       {
  1042.          printmsg(0,"Unable to set environment \"%s\"",envp[subscript]);
  1043.          panic();
  1044.       }
  1045.    } /* while */
  1046.  
  1047.    return envp;
  1048. } /* create_environment */
  1049.  
  1050. /*--------------------------------------------------------------------*/
  1051. /*    d e l e t e  _ e n v i r o n m e n t                            */
  1052. /*                                                                    */
  1053. /*    Delete variables inserted by create_enviroment                  */
  1054. /*                                                                    */
  1055. /*    Our environment goes away when we are done executing we; just   */
  1056. /*    clean up the environment because we are freeing the storage     */
  1057. /*--------------------------------------------------------------------*/
  1058.  
  1059. static void delete_environment( char **envp )
  1060. {
  1061.    int subscript = 0;
  1062.  
  1063.    while ( envp[subscript] != NULL )
  1064.    {
  1065.       char *equal = strchr(envp[subscript]  , '=' );
  1066.       *++equal = '\0';        /* Terminate the string             */
  1067.       if (putenv( envp[subscript] ))
  1068.       {
  1069.          printmsg(0,"Unable to reset environment \"%s\"",envp[subscript]);
  1070.          panic();
  1071.       }
  1072.       free( envp[subscript++] );
  1073.    }
  1074.  
  1075.    free( envp );
  1076. } /* delete_environment */
  1077.  
  1078.  
  1079. /*--------------------------------------------------------------------*/
  1080. /*    d o _ c o p y                                                   */
  1081. /*                                                                    */
  1082. /*    Send a file to remote node via uucp                             */
  1083. /*--------------------------------------------------------------------*/
  1084.  
  1085. static boolean do_copy(char *localfile,
  1086.                        const char *rmtsystem,
  1087.                        const char *remotefile,
  1088.                        const char *requestor,
  1089.                        const boolean success )
  1090. {
  1091.       if (rmtsystem == NULL) {
  1092.           copylocal(localfile, remotefile);
  1093.       } else {
  1094.           char    tmfile[FILENAME_MAX];  /* Unix style name for c file */
  1095.           char    idfile[FILENAME_MAX];  /* Unix style name for data file copy */
  1096.           char    work[FILENAME_MAX]; /* temp area for filename hacking */
  1097.           char    icfilename[FILENAME_MAX];  /* our hacked c file path */
  1098.           char    idfilename[FILENAME_MAX];  /* our hacked d file path */
  1099.  
  1100.           struct  stat    statbuf;
  1101.  
  1102.           long    int     sequence;
  1103.           static  char    subseq = 'A';
  1104.           char   *sequence_s;
  1105.           FILE   *cfile;
  1106.  
  1107.  
  1108.           sequence = getseq();
  1109.           sequence_s = JobNumber( sequence );
  1110.  
  1111.           sprintf(tmfile, spool_fmt, 'C', rmtsystem, 'Z', sequence_s);
  1112.           importpath(work, tmfile, rmtsystem);
  1113.           mkfilename(icfilename, E_spooldir, work);
  1114.  
  1115.           if (stat((char *) localfile, &statbuf) != 0)  {
  1116.               printerr( localfile );
  1117.               return FALSE;
  1118.           }
  1119.  
  1120.           sprintf(idfile , dataf_fmt, 'D', E_nodename, sequence_s,
  1121.                   (char) subseq++ );
  1122.           importpath(work, idfile, rmtsystem);
  1123.           mkfilename(idfilename, E_spooldir, work);
  1124.  
  1125.           if (!copylocal(localfile, idfilename))  {
  1126.              printmsg(0, "Copy \"%s\" to \"%s\" failed", localfile, idfilename);
  1127.              return FALSE;
  1128.           }
  1129.  
  1130.           if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)  {
  1131.              printerr( icfilename );
  1132.              printf("cannot append to %s\n", icfilename);
  1133.              return FALSE;
  1134.           }
  1135.  
  1136.           fprintf(cfile, send_cmd, localfile, remotefile,
  1137.                    "uucp" , success ? "n" : " ", idfile,
  1138.                     success ? requestor : " ");
  1139.  
  1140.           fclose(cfile);
  1141.     };
  1142.  
  1143.     return TRUE;
  1144. } /* do_copy */
  1145.  
  1146. /*--------------------------------------------------------------------*/
  1147. /*    R e p o r t R e s u l t s                                       */
  1148. /*                                                                    */
  1149. /*    report results of command execution as specified by flags in    */
  1150. /*    X.* file.                                                       */
  1151. /*--------------------------------------------------------------------*/
  1152.  
  1153. static void ReportResults(const int status,
  1154.                           const char *input,
  1155.                                 char *output,
  1156.                           const char *command,
  1157.                           const char *job_id,
  1158.                           const time_t jtime,
  1159.                           const char *requestor,
  1160.                           const char *outnode,
  1161.                           const char *outname,
  1162.                           const boolean xflag[],
  1163.                           const char *statfil,
  1164.                           const char *machine,
  1165.                           const char *user)
  1166. {
  1167.      char address[MAXADDR];
  1168.      char subject[80];
  1169.      FILE *mailtmp = NULL;
  1170.      char *tempmail = mktempname(NULL, "TMP");
  1171.  
  1172.  
  1173.      if (!(xflag[X_FAILED] | xflag[X_SUCCESS] |
  1174.            xflag[X_INPUT]  | xflag[X_STATFIL]))
  1175.      {  /* default actions */
  1176.          unlink(output);
  1177.          return;
  1178.      }
  1179.  
  1180.      if ((mailtmp = FOPEN(tempmail, "w+", BINARY_MODE)) == NULL) {
  1181.          printerr(tempmail);
  1182.          return;
  1183.      }
  1184.  
  1185.      sprintf(subject, "\"[uucp job %s (%s)]\"", job_id, dater(jtime, NULL) );
  1186.  
  1187.      fprintf(mailtmp,"remote execution\n");
  1188.      fprintf(mailtmp,"%s\n", command);
  1189.  
  1190. #ifdef BETA_TEST
  1191.      strcpy(address,"postmaster");
  1192. #else
  1193.      if (equal(machine, E_nodename))
  1194.         strcpy(address, requestor);
  1195.      else
  1196.         sprintf(address,"%s!%s", machine, requestor);
  1197. #endif
  1198.  
  1199.      if (xflag[E_NORMAL])
  1200.      {                        /* command succeded, process appropriate flags */
  1201.  
  1202.        fprintf(mailtmp,"exited normally\n");
  1203.  
  1204.        if (xflag[X_OUTPUT])
  1205.            do_copy(output, outnode, outname, requestor, xflag[X_SUCCESS]);
  1206.        else
  1207.            unlink(output);
  1208.  
  1209.        fclose(mailtmp);
  1210.  
  1211.        if (xflag[X_SUCCESS]) {
  1212.           if (xflag[X_STATFIL]) {
  1213.               do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1214.           } else {
  1215.               MailStatus(tempmail, address, subject);
  1216.           }
  1217.        };
  1218.  
  1219.    } else {            /* command failed, process appropriate flags   */
  1220.      if (xflag[E_NOACC])
  1221.          fprintf(mailtmp,"file access denied to %s!%s", machine, user);
  1222.      else if (xflag[E_NOEXE])
  1223.         fprintf(mailtmp,"execution permission denied to %s!%s\n",
  1224.                 machine, requestor);
  1225.      else if (xflag[E_SIGNAL])
  1226.         fprintf(mailtmp,"terminated by signal\n");
  1227.      else if (xflag[E_STATUS])
  1228.         fprintf(mailtmp,"exited with status %d\n", status);
  1229.      else /* xflag->e & E_FAILED */
  1230.         fprintf(mailtmp,"failed completely\n");
  1231.  
  1232.  
  1233.      if (xflag[E_STATUS]) {
  1234.        if ((xflag[X_FAILED]) && !(xflag[X_INPUT])) {
  1235.            fprintf(mailtmp,"===== error output not available =====\n");
  1236.        } else if ((xflag[X_FAILED]) && (xflag[X_INPUT])) {
  1237.            fprintf(mailtmp,"===== stdin was ");
  1238.  
  1239.            if (xflag[S_CORRUPT])
  1240.                fprintf(mailtmp,"unreadable =====\n");
  1241.            else if (xflag[S_EMPTY])
  1242.                fprintf(mailtmp,"empty =====\n");
  1243.            else if (xflag[S_NOREAD])
  1244.                fprintf(mailtmp,"denied read permission =====\n");
  1245.            else {
  1246.                fprintf(mailtmp,"=====\n");
  1247.                AppendData( input, mailtmp);
  1248.            };
  1249.            unlink(input);
  1250.  
  1251.            fprintf(mailtmp,"===== stderr is unavailable =====\n");
  1252.        }
  1253.      }
  1254.  
  1255.      fclose(mailtmp);
  1256.  
  1257.      if (xflag[X_STATFIL]) {
  1258.          do_copy(tempmail, outnode, statfil, requestor, xflag[X_SUCCESS]);
  1259.      } else {
  1260.          MailStatus(tempmail, address, subject);
  1261.      }
  1262.  
  1263.    }
  1264.  
  1265.    if (xflag[X_OUTPUT])
  1266.        unlink(output);
  1267.  
  1268.    unlink(tempmail);
  1269.    return;
  1270. } /* ReportResults */
  1271.  
  1272. /*--------------------------------------------------------------------*/
  1273. /* A p p e n d D a t a                                                */
  1274. /*                                                                    */
  1275. /* Append data to output file                                         */
  1276. /*--------------------------------------------------------------------*/
  1277.  
  1278. static boolean AppendData( const char *input, FILE* dataout)
  1279. {
  1280.    FILE    *datain;
  1281.    char     buf[BUFSIZ];
  1282.    boolean  status = TRUE;
  1283.  
  1284. /*--------------------------------------------------------------------*/
  1285. /*                      Verify the input opened                       */
  1286. /*--------------------------------------------------------------------*/
  1287.  
  1288.    if (input == NULL)
  1289.       return FALSE;
  1290.    else
  1291.       datain = FOPEN(input, "r",TEXT_MODE);
  1292.  
  1293.    if (datain == NULL) {
  1294.       printerr(input);
  1295.       printmsg(0,"Unable to open input file \"%s\"", input);
  1296.       return FALSE;
  1297.    } /* datain */
  1298.  
  1299. /*--------------------------------------------------------------------*/
  1300. /*                       Loop to copy the data                        */
  1301. /*--------------------------------------------------------------------*/
  1302.  
  1303.    while (fgets(buf, BUFSIZ, datain) != 0)
  1304.    {
  1305.       if (fputs(buf, dataout) == EOF)     /* I/O error?               */
  1306.       {
  1307.          printmsg(0,"AppendData: I/O error on output file");
  1308.          printerr("dataout");
  1309.          fclose(datain);
  1310.          return FALSE;
  1311.       } /* if */
  1312.    } /* while */
  1313.  
  1314. /*--------------------------------------------------------------------*/
  1315. /*                      Close up shop and return                      */
  1316. /*--------------------------------------------------------------------*/
  1317.  
  1318.    if (ferror(datain))        /* Clean end of file on input?          */
  1319.    {
  1320.       printerr(input);
  1321.       clearerr(datain);
  1322.       status = FALSE;
  1323.    }
  1324.  
  1325.    fclose(datain);
  1326.    return status;
  1327.  
  1328. } /* AppendData */
  1329.  
  1330. /*--------------------------------------------------------------------*/
  1331. /*    M a i l S t a t u s                                             */
  1332. /*                                                                    */
  1333. /*    Send text in a mailbag file to address(es) specified by line.   */
  1334. /*--------------------------------------------------------------------*/
  1335.  
  1336. static boolean MailStatus(char *tempfile,
  1337.                           char *address,
  1338.                           char *subject)
  1339. {
  1340.    boolean status;
  1341.    char **envp;
  1342.  
  1343. /*--------------------------------------------------------------------*/
  1344. /*                            Invoke RMAIL                            */
  1345. /*--------------------------------------------------------------------*/
  1346.  
  1347.    envp = create_environment( "uucp", NULL );
  1348.  
  1349.    if ( subject == NULL )
  1350.       status = spawnlp( P_WAIT, RMAIL, RMAIL,
  1351.                         "-f", tempfile, "-w", address, NULL);
  1352.    else
  1353.       status = spawnlp( P_WAIT, RMAIL, RMAIL,
  1354.                         "-f", tempfile, "-w", "-s", subject, address, NULL);
  1355.  
  1356.    delete_environment( envp );
  1357.  
  1358. /*--------------------------------------------------------------------*/
  1359. /*                       Report errors, if any                        */
  1360. /*--------------------------------------------------------------------*/
  1361.  
  1362.    if ( status < 0 )
  1363.    {
  1364.       printerr( RMAIL );
  1365.       printmsg(0,"Unable to execute rmail; status not delivered.");
  1366.    }
  1367.    else if ( status > 0 )
  1368.       printmsg(0, "Rmail returned error;\
  1369.  status delivery may be incomplete.");
  1370.  
  1371. /*--------------------------------------------------------------------*/
  1372. /*                          Return to caller                          */
  1373. /*--------------------------------------------------------------------*/
  1374.  
  1375.    return (status == 0 );
  1376.  
  1377. } /*MailStatus*/
  1378.  
  1379. /*--------------------------------------------------------------------*/
  1380. /*    i n t e r n a l                                                 */
  1381. /*                                                                    */
  1382. /*    Determine if command is internal DOS command                    */
  1383. /*--------------------------------------------------------------------*/
  1384.  
  1385. static boolean internal( char *command )
  1386. {
  1387.    static char *commands[] = { "break",   "cd",    "chdir",    "copy",
  1388.                                "ctty",    "date",  "del",      "dir",
  1389.                                "echo",    "erase", "for",      "md",
  1390.                                "mkdir",   "rd",    "rem",      "ren",
  1391.                                "rename",  "rmdir", "time",     "ver",
  1392.                                "verify",  "vol",
  1393.                                NULL };
  1394.    char **list;
  1395.  
  1396. /*--------------------------------------------------------------------*/
  1397. /*                   Determine command list to use                    */
  1398. /*--------------------------------------------------------------------*/
  1399.  
  1400.    if (E_internal == NULL )
  1401.       list = commands;
  1402.    else
  1403.       list = E_internal;
  1404.  
  1405. /*--------------------------------------------------------------------*/
  1406. /*                   Scan the list for the command                    */
  1407. /*--------------------------------------------------------------------*/
  1408.  
  1409.    while( *list != NULL )
  1410.    {
  1411.       printmsg(5,"Searching for \"%s\", comparing to \"%s\"",
  1412.                   *list, command);
  1413.       if (equali(*list++,command))
  1414.       {
  1415.          printmsg(4,"\"%s\" is an internal command",command);
  1416.          return TRUE;
  1417.       } /* if */
  1418.    } /* while( *list != NULL ) */
  1419.  
  1420. /*--------------------------------------------------------------------*/
  1421. /*  The command is not in the list; return FALSE (external command)   */
  1422. /*--------------------------------------------------------------------*/
  1423.  
  1424.    printmsg(4,"\"%s\" is an external command",command);
  1425.    return FALSE;
  1426.  
  1427. } /* internal */
  1428.